/* Copyright (c) 2004-2024 Peigen.info. All rights reserved. */

package info.peigen.hotpot.business.account.base;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import info.peigen.hotpot.business.account.core.repository.entity.AccountEntity;
import info.peigen.hotpot.business.account.core.repository.entity.AccountFreezeLogEntity;
import info.peigen.hotpot.business.account.core.repository.entity.AccountLogEntity;
import info.peigen.hotpot.business.account.core.repository.entity.AccountTransLogEntity;
import info.peigen.hotpot.business.account.core.service.AccountFreezeService;
import info.peigen.hotpot.business.account.core.service.AccountService;
import info.peigen.hotpot.business.account.core.service.AccountTransService;
import info.peigen.hotpot.business.account.core.service.query.QueryAccountLogService;
import info.peigen.hotpot.business.account.core.service.query.QueryAccountService;
import info.peigen.hotpot.business.account.facade.enums.AccountTransCode;
import info.peigen.hotpot.business.account.facade.order.create.*;
import info.peigen.hotpot.business.account.facade.order.freeze.FreezeAccountOrder;
import info.peigen.hotpot.business.account.facade.order.freeze.FreezeAmountOrder;
import info.peigen.hotpot.business.account.facade.order.freeze.UnfreezeAccountOrder;
import info.peigen.hotpot.business.account.facade.order.freeze.UnfreezeAmountOrder;
import info.peigen.hotpot.business.account.facade.order.trans.TransferOrder;
import info.peigen.hotpot.business.account.facade.order.trans.fee.FeeOrderInfo;
import info.peigen.hotpot.business.account.facade.result.create.CreateAccountResult;
import info.peigen.hotpot.business.account.facade.result.trans.TransferResult;
import info.peigen.hotpot.business.router.core.repository.entity.RouterChannelEntity;
import info.peigen.hotpot.business.router.facade.enums.ChannelBusinessType;
import info.peigen.hotpot.business.router.facade.enums.ChannelCode;
import info.peigen.hotpot.business.router.facade.enums.ChannelCurrencyType;
import info.peigen.hotpot.common.core.enums.Currency;
import info.peigen.hotpot.common.core.lang.money.Money;
import info.peigen.hotpot.common.core.result.ResultCode;
import info.peigen.hotpot.common.core.result.ResultStatus;
import info.peigen.hotpot.common.core.util.IdUtil;
import info.peigen.hotpot.common.service.base.processor.ProcessorServiceContext;
import info.peigen.hotpot.common.service.base.test.ServiceTestContext;
import info.peigen.hotpot.common.service.base.test.ServiceTestInvoke;
import info.peigen.hotpot.common.service.base.test.mock.ServiceTestMockContext;
import info.peigen.hotpot.common.service.base.test.mock.ServiceTestMockContextThreadLocal;
import lombok.AccessLevel;
import lombok.experimental.FieldDefaults;
import org.junit.jupiter.api.Assertions;
import org.noear.solon.annotation.Inject;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

import static info.peigen.hotpot.business.account.facade.enums.AccountAction.*;
import static info.peigen.hotpot.business.account.facade.enums.AccountFeeAction.Charge;
import static info.peigen.hotpot.business.account.facade.enums.AccountTransCode.Deposit;
import static info.peigen.hotpot.business.account.facade.enums.AccountTransCode.Transfer;
import static info.peigen.hotpot.business.router.facade.enums.ChannelCode.Weixin;
import static info.peigen.hotpot.common.core.enums.Currency.*;

/**
 * <b>(AccountServiceTestBase)</b>
 *
 * @author Peigen
 * @version 1.0.0
 * @since 2021/7/31
 */
@FieldDefaults(level = AccessLevel.PROTECTED)
public class AccountServiceTestBase extends AccountRepositoryTestBase {
    @Inject
    QueryAccountLogService queryAccountLogService;
    @Inject
    QueryAccountService    queryAccountService;
    @Inject
    AccountService         accountService;
    @Inject
    AccountTransService    accountTransService;
    @Inject
    AccountFreezeService   accountFreezeService;

    protected String createCustomerAccount(String customerId) {
        ServiceTestContext serviceTestContext = ServiceTestContext.builder().resultStatus(ResultStatus.success).resultCode(ResultCode.SUCCESS).build();

        new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().expectResultStatus(ResultStatus.success).expectResultCode(ResultCode.SUCCESS).expectErrorCode("").build());
        executeTest(serviceTestContext, new ServiceTestInvoke() {
            @Override
            public void cleanData() {
                accountRepository.getMapper().deleteByCustomerId(customerId);
            }

            @Override
            public void initData(ServiceTestContext serviceTestContext) {
                CreateCustomerAccountOrder order = genCreateCustomerAccountOrder().setCustomerId(customerId);
                order.setPartnerId(PARTNER_ID);
                serviceTestContext.setOrder(order);
                serviceTestContext.setSingleResult(new CreateAccountResult());
                serviceTestContext.setServiceContext(ProcessorServiceContext.builder().order(order).result(serviceTestContext.getSingleResult()).build());
            }

            @Override
            public void callService(ServiceTestContext serviceTestContext) {
                CreateCustomerAccountOrder order  = (CreateCustomerAccountOrder) serviceTestContext.getOrder();
                CreateAccountResult        result = accountService.createCustomerAccount(order);
                serviceTestContext.setSingleResult(result);
            }

            @Override
            public void dataAssert(ServiceTestContext serviceTestContext) {
                AccountEntity entity = accountRepository.getMapper().findByCustomerId(customerId);
                Assertions.assertNotNull(entity);
                Assertions.assertTrue(StrUtil.equals(entity.getCustomerId(), customerId));
            }
        });
        return ((CreateAccountResult) serviceTestContext.getSingleResult()).getInfo().getAccountId();
    }

    protected String createCustomerAccount(String customerId, ResultStatus resultStatus, ResultCode resultCode, String detail) {
        ServiceTestContext serviceTestContext = ServiceTestContext.builder().resultStatus(resultStatus).resultCode(resultCode).build();
        new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().expectResultStatus(resultStatus).expectResultCode(resultCode).expectErrorCode(detail).build());

        executeTest(serviceTestContext, new ServiceTestInvoke() {
            @Override
            public void cleanData() {
                accountRepository.getMapper().deleteByCustomerId(customerId);
            }

            @Override
            public void initData(ServiceTestContext serviceTestContext) {
                CreateCustomerAccountOrder order = genCreateCustomerAccountOrder().setCustomerId(customerId);
                order.setPartnerId(PARTNER_ID);
                serviceTestContext.setOrder(order);
                serviceTestContext.setSingleResult(new CreateAccountResult());
                serviceTestContext.setServiceContext(ProcessorServiceContext.builder().order(order).result(serviceTestContext.getSingleResult()).build());
            }

            @Override
            public void callService(ServiceTestContext serviceTestContext) {
                CreateCustomerAccountOrder order  = (CreateCustomerAccountOrder) serviceTestContext.getOrder();
                CreateAccountResult        result = accountService.createCustomerAccount(order);
                serviceTestContext.setSingleResult(result);
            }

            @Override
            public void dataAssert(ServiceTestContext serviceTestContext) {
                AccountEntity entity = accountRepository.getMapper().findByCustomerId(customerId);
                Assertions.assertNotNull(entity);
                Assertions.assertTrue(StrUtil.equals(entity.getCustomerId(), customerId));
            }
        });
        return ((CreateAccountResult) serviceTestContext.getSingleResult()).getInfo().getAccountId();
    }

    protected String createPartnerAccount(String partnerId, String aliasName, ResultStatus resultStatus, ResultCode resultCode, String detail) {
        ServiceTestContext serviceTestContext = ServiceTestContext.builder().resultStatus(resultStatus).resultCode(resultCode).build();

        new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().expectResultStatus(resultStatus).expectResultCode(resultCode).expectErrorCode(detail).build());
        executeTest(serviceTestContext, new ServiceTestInvoke() {
            @Override
            public void cleanData() {
                accountRepository.getMapper().deleteByCustomerId(partnerId);
            }

            @Override
            public void initData(ServiceTestContext serviceTestContext) {
                CreatePartnerAccountOrder order = genCreatePartnerAccountOrder().setPartnerId(partnerId).setAliasName(aliasName);
                serviceTestContext.setOrder(order);
                serviceTestContext.setSingleResult(new CreateAccountResult());
                serviceTestContext.setServiceContext(ProcessorServiceContext.builder().order(order).result(serviceTestContext.getSingleResult()).build());
            }

            @Override
            public void callService(ServiceTestContext serviceTestContext) {
                CreatePartnerAccountOrder order  = (CreatePartnerAccountOrder) serviceTestContext.getOrder();
                CreateAccountResult       result = accountService.createPartnerAccount(order);
                serviceTestContext.setSingleResult(result);
            }

            @Override
            public void dataAssert(ServiceTestContext serviceTestContext) {
                AccountEntity entity = accountRepository.getMapper().findByCustomerId(partnerId);
                Assertions.assertNotNull(entity);
                Assertions.assertTrue(StrUtil.equals(entity.getCustomerId(), partnerId));
            }
        });
        return ((CreateAccountResult) serviceTestContext.getSingleResult()).getInfo().getAccountId();
    }

    protected String createProvisionsAccount(String aliasName, ResultStatus resultStatus, ResultCode resultCode, String detail) {
        ServiceTestContext serviceTestContext = ServiceTestContext.builder().resultStatus(resultStatus).resultCode(resultCode).build();

        new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().expectResultStatus(resultStatus).expectResultCode(resultCode).expectErrorCode(detail).build());
        executeTest(serviceTestContext, new ServiceTestInvoke() {
            @Override
            public void cleanData() {
                accountRepository.getMapper().deleteByAliasName(aliasName);
            }

            @Override
            public void initData(ServiceTestContext serviceTestContext) {
                CreateProvisionsAccountOrder order = genCreateProvisionsAccountOrder().setAliasName(aliasName);
                order.setPartnerId(PARTNER_ID);
                serviceTestContext.setOrder(order);
                serviceTestContext.setSingleResult(new CreateAccountResult());
                serviceTestContext.setServiceContext(ProcessorServiceContext.builder().order(order).result(serviceTestContext.getSingleResult()).build());
            }

            @Override
            public void callService(ServiceTestContext serviceTestContext) {
                CreateProvisionsAccountOrder order  = (CreateProvisionsAccountOrder) serviceTestContext.getOrder();
                CreateAccountResult          result = accountService.createProvisionsAccount(order);
                serviceTestContext.setSingleResult(result);
            }

            @Override
            public void dataAssert(ServiceTestContext serviceTestContext) {
                String        accountId = ((CreateAccountResult) serviceTestContext.getSingleResult()).getInfo().getAccountId();
                AccountEntity entity    = accountRepository.getMapper().findByAccountId(accountId);
                Assertions.assertNotNull(entity);
                Assertions.assertTrue(StrUtil.equals(entity.getAliasName(), aliasName));
            }
        });
        return ((CreateAccountResult) serviceTestContext.getSingleResult()).getInfo().getAccountId();
    }

    protected String createIntermediateAccount(String partnerId, String aliasName, ResultStatus resultStatus, ResultCode resultCode, String detail) {
        ServiceTestContext serviceTestContext = ServiceTestContext.builder().resultStatus(resultStatus).resultCode(resultCode).build();

        new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().expectResultStatus(resultStatus).expectResultCode(resultCode).expectErrorCode(detail).build());
        executeTest(serviceTestContext, new ServiceTestInvoke() {
            @Override
            public void cleanData() {
                accountRepository.getMapper().deleteByCustomerId(partnerId);
            }

            @Override
            public void initData(ServiceTestContext serviceTestContext) {
                CreateIntermediateAccountOrder order = genCreateIntermediateAccountOrder().setPartnerId(partnerId).setAliasName(aliasName);
                serviceTestContext.setOrder(order);
                serviceTestContext.setSingleResult(new CreateAccountResult());
                serviceTestContext.setServiceContext(ProcessorServiceContext.builder().order(order).result(serviceTestContext.getSingleResult()).build());
            }

            @Override
            public void callService(ServiceTestContext serviceTestContext) {
                CreateIntermediateAccountOrder order  = (CreateIntermediateAccountOrder) serviceTestContext.getOrder();
                CreateAccountResult            result = accountService.createIntermediateAccount(order);
                serviceTestContext.setSingleResult(result);
            }

            @Override
            public void dataAssert(ServiceTestContext serviceTestContext) {
                AccountEntity entity = accountRepository.getMapper().findByCustomerId(partnerId);
                Assertions.assertNotNull(entity);
                Assertions.assertTrue(StrUtil.equals(entity.getCustomerId(), partnerId));
            }

        });
        return ((CreateAccountResult) serviceTestContext.getSingleResult()).getInfo().getAccountId();
    }

    protected String createFeeAccount(String aliasName, ResultStatus resultStatus, ResultCode resultCode, String detail) {
        ServiceTestContext serviceTestContext = ServiceTestContext.builder().resultStatus(resultStatus).resultCode(resultCode).build();

        new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().expectResultStatus(resultStatus).expectResultCode(resultCode).expectErrorCode(detail).build());
        executeTest(serviceTestContext, new ServiceTestInvoke() {
            @Override
            public void cleanData() {
                accountRepository.getMapper().deleteByAliasName(aliasName);
            }

            @Override
            public void initData(ServiceTestContext serviceTestContext) {
                CreateFeeAccountOrder order = genCreateFeeAccountOrder().setAliasName(aliasName);
                order.setPartnerId(PARTNER_ID);
                serviceTestContext.setOrder(order);
                serviceTestContext.setSingleResult(new CreateAccountResult());
                serviceTestContext.setServiceContext(ProcessorServiceContext.builder().order(order).result(serviceTestContext.getSingleResult()).build());
            }

            @Override
            public void callService(ServiceTestContext serviceTestContext) {
                CreateFeeAccountOrder order  = (CreateFeeAccountOrder) serviceTestContext.getOrder();
                CreateAccountResult   result = accountService.createFeeAccount(order);
                serviceTestContext.setSingleResult(result);
            }

            @Override
            public void dataAssert(ServiceTestContext serviceTestContext) {
                String        accountId = ((CreateAccountResult) serviceTestContext.getSingleResult()).getInfo().getAccountId();
                AccountEntity entity    = accountRepository.getMapper().findByAccountId(accountId);
                Assertions.assertNotNull(entity);
                Assertions.assertTrue(StrUtil.equals(entity.getAliasName(), aliasName));
            }
        });
        return ((CreateAccountResult) serviceTestContext.getSingleResult()).getInfo().getAccountId();
    }

    protected TransferResult accountDeposit(String accountId, Money amount, String tradeId) {

        return accountDeposit(accountId, amount, tradeId, new Date(), null, "充值-不收费", ResultStatus.success, ResultCode.SUCCESS, "");
    }

    protected TransferResult accountDeposit(String accountId, Money amount, String tradeId, Date settleTime, FeeOrderInfo feeOrderInfo, String memo, ResultStatus resultStatus, ResultCode resultCode, String detail) {
        ServiceTestContext serviceTestContext = ServiceTestContext.builder().resultStatus(resultStatus).resultCode(resultCode).build();

        new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().expectResultStatus(resultStatus).expectResultCode(resultCode).expectErrorCode(detail).build());
        executeTest(serviceTestContext, new ServiceTestInvoke() {
            @Override
            public void cleanData() {
                accountRepository.getAccountLogRepository().deleteByTradeId(tradeId);
            }

            @Override
            public void initData(ServiceTestContext serviceTestContext) {
                TransferOrder order = genDepositOrder().setPayeeAccountId(accountId);
                order.setTransAmount(amount).setTradeId(tradeId).setSettleTime(settleTime).setMemo(memo)
                        .setFeeOrderInfo(feeOrderInfo);

                if (ObjectUtil.isNull(feeOrderInfo)) {
                    order.setFeeOrderInfo(genFreeFeeOrderInfo(accountId));
                }

                serviceTestContext.setOrder(order);
                serviceTestContext.setSingleResult(new TransferResult());
                serviceTestContext.setServiceContext(ProcessorServiceContext.builder().order(order).result(serviceTestContext.getSingleResult()).build());
            }

            @Override
            public void callService(ServiceTestContext serviceTestContext) {
                TransferOrder  order  = (TransferOrder) serviceTestContext.getOrder();
                TransferResult result = accountTransService.deposit(order);
                serviceTestContext.setSingleResult(result);
            }

            @Override
            public void dataAssert(ServiceTestContext serviceTestContext) {
                if (serviceTestContext.getSingleResult().failure()) {
                    return;
                }

                AccountEntity entity = accountRepository.getMapper().findByAccountId(accountId);
                Assertions.assertNotNull(entity);

                // 客户账户记录检查
                AccountLogEntity logEntity = accountRepository.getAccountLogRepository().findByTradeIdAndTransCodeAndAccountId(tradeId, AccountTransCode.Income, accountId);
                Assertions.assertNotNull(logEntity);
                Assertions.assertTrue(logEntity.getTransAmount().greaterThan(Money.zero()));
                Assertions.assertTrue(logEntity.getTransAmount().equals(amount));

                // 备付金账户记录检查
                AccountEntity provisionsEntity = accountRepository.getMapper().findProvisionsAccountByCode(Weixin);
                Assertions.assertNotNull(provisionsEntity);
                AccountLogEntity provisionsLogEntity = accountRepository.getAccountLogRepository().findByTradeIdAndTransCodeAndAccountId(tradeId, AccountTransCode.Income, provisionsEntity.getAccountId());
                Assertions.assertNotNull(provisionsLogEntity);
                Assertions.assertTrue(provisionsLogEntity.getTransAmount().greaterThan(Money.zero()));
                Assertions.assertTrue(provisionsLogEntity.getTransAmount().equals(amount));

                // 收费记录检查
                if (ObjectUtil.isNotNull(feeOrderInfo)) {
                    AccountLogEntity payerLogEntity = accountRepository.getAccountLogRepository().findByTradeIdAndTransCodeAndAccountId(tradeId, AccountTransCode.Fee, feeOrderInfo.getPayerAccountId());
                    Assertions.assertNotNull(payerLogEntity);
                    Assertions.assertTrue(payerLogEntity.getTransAmount().equals(feeOrderInfo.getFeeAmount()));

                    AccountLogEntity payeeLogEntity = accountRepository.getAccountLogRepository().findByTradeIdAndTransCodeAndAccountId(tradeId, AccountTransCode.Fee, feeOrderInfo.getPayeeAccountId());
                    Assertions.assertNotNull(payeeLogEntity);
                    Assertions.assertTrue(payeeLogEntity.getTransAmount().equals(feeOrderInfo.getFeeAmount()));
                }
            }
        });
        return (TransferResult) serviceTestContext.getSingleResult();
    }

    protected TransferResult accountTransfer(String payerAccountId, String payeeAccountId, Money amount, String tradeId, Date settleTime, FeeOrderInfo feeOrderInfo, String memo, ResultStatus resultStatus, ResultCode resultCode, String detail) {
        ServiceTestContext serviceTestContext = ServiceTestContext.builder().resultStatus(resultStatus).resultCode(resultCode).build();

        new ServiceTestMockContextThreadLocal(ServiceTestMockContext.builder().expectResultStatus(resultStatus).expectResultCode(resultCode).expectErrorCode(detail).build());
        executeTest(serviceTestContext, new ServiceTestInvoke() {
            @Override
            public void cleanData() {
                accountRepository.getAccountLogRepository().deleteByTradeId(tradeId);
                accountRepository.getAccountTransLogRepository().deleteByTradeId(tradeId);
            }

            @Override
            public void initData(ServiceTestContext serviceTestContext) {
                TransferOrder order = genTransferOrder().setPayerAccountId(payerAccountId).setPayeeAccountId(payeeAccountId);
                order.setTransAmount(amount).setTradeId(tradeId).setSettleTime(settleTime).setMemo(memo);

                if (ObjectUtil.isNull(feeOrderInfo)) {
                    order.setFeeOrderInfo(genFreeFeeOrderInfo(payerAccountId));
                }

                serviceTestContext.setOrder(order);
                serviceTestContext.setSingleResult(new TransferResult());
                serviceTestContext.setServiceContext(ProcessorServiceContext.builder().order(order).result(serviceTestContext.getSingleResult()).build());
            }

            @Override
            public void callService(ServiceTestContext serviceTestContext) {
                TransferOrder  order  = (TransferOrder) serviceTestContext.getOrder();
                TransferResult result = accountTransService.transfer(order);
                serviceTestContext.setSingleResult(result);
            }

            @Override
            public void dataAssert(ServiceTestContext serviceTestContext) {
                TransferResult result      = (TransferResult) serviceTestContext.getSingleResult();
                AccountEntity  payerEntity = accountRepository.getMapper().findByAccountId(payerAccountId);
                Assertions.assertNotNull(payerEntity);

                AccountEntity payeeEntity = accountRepository.getMapper().findByAccountId(payeeAccountId);
                Assertions.assertNotNull(payeeEntity);

                // accountLog assert
                AccountLogEntity payerLogEntity = accountRepository.getAccountLogRepository().findByTradeIdAndTransCodeAndAccountId(tradeId, AccountTransCode.Paid, payerAccountId);
                Assertions.assertNotNull(payerLogEntity);
                Assertions.assertTrue(payerLogEntity.getTransAmount().greaterThan(Money.zero()));
                Assertions.assertTrue(payerLogEntity.getTransAmount().equals(amount));

                AccountLogEntity payeeLogEntity = accountRepository.getAccountLogRepository().findByTradeIdAndTransCodeAndAccountId(tradeId, AccountTransCode.Income, payeeAccountId);
                Assertions.assertNotNull(payeeLogEntity);
                Assertions.assertTrue(payeeLogEntity.getTransAmount().greaterThan(Money.zero()));
                Assertions.assertTrue(payeeLogEntity.getTransAmount().equals(amount));

                // transLog assert
                AccountTransLogEntity transLogEntity = accountRepository.getAccountTransLogRepository().findByTransLogId(result.getTransLogId());
                Assertions.assertNotNull(transLogEntity);
                Assertions.assertTrue(transLogEntity.getTransAmount().equals(amount));
            }
        });
        return (TransferResult) serviceTestContext.getSingleResult();
    }

    protected void deleteChannel(ChannelCode channelCode, ChannelBusinessType type, Currency currency) {
        if (channelCode == Weixin) {
            List<RouterChannelEntity> entities = defaultReceiptChannel();
            entities.forEach(entity -> routerChannelRepository.getMapper().deleteByCodeAndTypeAndCurrency(channelCode, type, entity.getCurrency()));
            return;
        }

        routerChannelRepository.getMapper().deleteByCodeAndTypeAndCurrency(channelCode, type, currency);
    }

    protected List<RouterChannelEntity> defaultReceiptChannel() {
        RouterChannelEntity entity = RouterChannelEntity.builder().channelId(IdUtil.id()).channelCode(Weixin).channelBusinessType(ChannelBusinessType.Receipt).channelCurrencyType(ChannelCurrencyType.Multi).currency(chooseCurrency(Weixin)).build();
        return Lists.newArrayList(entity, BeanUtil.copyProperties(entity, RouterChannelEntity.class).setChannelId(IdUtil.nextId(entity.getChannelId(), 1)).setCurrency(JPY), BeanUtil.copyProperties(entity, RouterChannelEntity.class).setChannelId(IdUtil.nextId(entity.getChannelId(), 2)).setCurrency(HKD), BeanUtil.copyProperties(entity, RouterChannelEntity.class).setChannelId(IdUtil.nextId(entity.getChannelId(), 3)).setCurrency(CNY), BeanUtil.copyProperties(entity, RouterChannelEntity.class).setChannelId(IdUtil.nextId(entity.getChannelId(), 4)).setCurrency(GBP), BeanUtil.copyProperties(entity, RouterChannelEntity.class).setChannelId(IdUtil.nextId(entity.getChannelId(), 5)).setCurrency(EUR));
    }

    protected Currency chooseCurrency(ChannelCode code) {
        switch (code) {
            case Weixin:
            case Pingan:
            case YIJIFU:
                return CNY;
            default:
                return null;
        }
    }

    protected CreateCustomerAccountOrder genCreateCustomerAccountOrder() {
        return CreateCustomerAccountOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(CreateCustomerAccount.code()).build();
    }

    protected CreateProvisionsAccountOrder genCreateProvisionsAccountOrder() {
        return CreateProvisionsAccountOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(CreateProvisionsAccount.code()).code(Weixin).build();
    }

    protected CreateIntermediateAccountOrder genCreateIntermediateAccountOrder() {
        return CreateIntermediateAccountOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(CreateIntermediateAccount.code()).build();
    }

    protected CreatePartnerAccountOrder genCreatePartnerAccountOrder() {
        return CreatePartnerAccountOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(CreatePartnerAccount.code()).build();
    }

    protected CreateFeeAccountOrder genCreateFeeAccountOrder() {
        return CreateFeeAccountOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(CreateFeeAccount.code()).build();
    }

    protected FreezeAccountOrder genFreezeAccountOrder() {
        return FreezeAccountOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(FreezeAccount.code()).build();
    }

    protected UnfreezeAccountOrder genUnfreezeAccountOrder() {
        return UnfreezeAccountOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(UnfreezeAccount.code()).build();
    }

    protected FreezeAmountOrder genFreezeAmountOrder() {
        return FreezeAmountOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(FreezeAmount.code()).build();
    }

    protected UnfreezeAmountOrder genUnfreezeAmountOrder() {
        return UnfreezeAmountOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(UnfreezeAmount.code()).build();
    }

    protected TransferOrder genTransferOrder() {
        return TransferOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(Transfer.code()).build();
    }

    protected TransferOrder genDepositOrder() {
        return TransferOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(Deposit.code()).build();
    }

    protected FreezeAmountOrder genFreezeAccountCapitalOrder() {
        return FreezeAmountOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(FreezeAmount.code()).build();
    }

    protected UnfreezeAmountOrder genUnfreezeAccountCapitalOrder() {
        return UnfreezeAmountOrder.builder().bizOrderNo(RandomUtil.randomString(20)).productCode(UnfreezeAmount.code()).build();
    }

    protected FeeOrderInfo genFreeFeeOrderInfo(String payerAccountId) {
        String payeeAccountId = accountRepository.getMapper().findFeeAccount().getAccountId();
        return FeeOrderInfo.freeOrderInfo(payerAccountId, payeeAccountId);
    }

    protected FeeOrderInfo genFeeOrderInfo(String payerAccountId, Money feeAmount) {
        String payeeAccountId = accountRepository.getMapper().findFeeAccount().getAccountId();
        return FeeOrderInfo.freeOrderInfo(payerAccountId, payeeAccountId).setFeeAmount(feeAmount).setAction(Charge);
    }

    protected void cleanAccount(String... accountId) {
        List<String> accountIds = Arrays.asList(accountId);
        accountIds.stream().forEach(aid -> accountRepository.getMapper().deleteByAccountId(aid));
    }

    protected void cleanLog(String... tradeId) {
        List<String> tradeIds = Arrays.asList(tradeId);
        accountRepository.getAccountLogRepository().getMapper().createLambdaQuery().andIn(AccountLogEntity::getTradeId, tradeIds).delete();
        accountRepository.getAccountTransLogRepository().getMapper().createLambdaQuery().andIn(AccountTransLogEntity::getTradeId, tradeIds).delete();
        accountRepository.getAccountFreezeLogRepository().getMapper().createLambdaQuery().andIn(AccountFreezeLogEntity::getTradeId, tradeIds).delete();
    }
}